<!doctype html>
<html lang="zh-cn">
<head>

    <meta charset="utf-8">
    <meta name="generator" content="Hugo 0.57.2" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Rust Ownership | The Sky of OtsWang</title>
    <meta property="og:title" content="Rust Ownership - The Sky of OtsWang">
    <meta property="og:type" content="article">
        
    <meta property="article:published_time" content="2019-07-24T10:37:36&#43;08:00">
        
        
    <meta property="article:modified_time" content="2019-07-24T10:37:36&#43;08:00">
        
    <meta name="Keywords" content="golang,go语言,otswang,java,博客,python">
    <meta name="description" content="Rust Ownership">
        
    <meta name="author" content="OtsWang">
    <meta property="og:url" content="https://otswang.gitee.io/hugo/post/lang/rust-ownership/">
    <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">

    <link rel="stylesheet" href="/hugo/css/normalize.css">
    
        <link rel="stylesheet" href="/hugo/css/prism.css">
    
    <link rel="stylesheet" href="/hugo/css/style.css">
    <script type="text/javascript" src="//cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>

    


    
    
</head>

<body>
<header id="header" class="clearfix">
    <div class="container">
        <div class="col-group">
            <div class="site-name ">
                
                    <a id="logo" href="https://otswang.gitee.io/hugo/">
                        The Sky of OtsWang
                    </a>
                
                <p class="description">擅长写HelloWorld的小小码农</p>
            </div>
            <div>
                <nav id="nav-menu" class="clearfix">
                    
                    
                    <a  href="https://otswang.gitee.io/hugo/" title="Home">Home</a>
                    
                    <a  href="https://otswang.gitee.io/hugo/tags/" title="Tags">Tags</a>
                    
                    <a  href="https://otswang.gitee.io/hugo/categories/" title="Categories">Categories</a>
                    
                    <a  href="https://otswang.gitee.io/hugo/archives/" title="Archives">Archives</a>
                    
                    <a  href="https://otswang.gitee.io/hugo/about/" title="About">About</a>
                    
                </nav>
            </div>
        </div>
    </div>
</header>


<div id="body">
    <div class="container">
        <div class="col-group">

            <div class="col-8" id="main">
                <div class="res-cons">
                    <article class="post">
                        <header>
                            <h1 class="post-title">Rust Ownership</h1>
                        </header>
                        <date class="post-meta meta-date">
                            2019年7月24日
                        </date>
                        
                        <div class="post-meta">
                            <span>|</span>
                            
                                <span class="meta-category"><a href="https://otswang.gitee.io/hugo/categories/%E5%B0%8F%E4%BC%97%E8%AF%AD%E8%A8%80%E4%B8%80%E7%9E%A5">小众语言一瞥</a></span>
                            
                        </div>
                        
                        
                        
                        <div class="post-content">
                            <p>对rust的所有权（ownership）概念的学习。</p>

<p>所有权是rust的一个核心概念，虽然所有权的字面意思是很容易理解，但是它对rust具有深远的意义。</p>

<p>几乎任何编程语言都需要在运行期管理(manager)对计算机内存的使用情况。一些语言使用garbage collection（内存回收）机制来管理不再使用的内存区域；一些语言使用明确的内存创建和释放命令来管理内存；而rust采用了第三种方法，通过一套复杂的所有权系统来管理内存，编译器在编译阶段检查变量的所有权，因此，所有权的出现不会对程序运行期的执行效率造成影响。</p>

<p>下面通过一些关于<code>string</code>的例子来解释所有权的相关概念。</p>

<h2 id="堆-heap-栈-stack">堆(heap)栈(stack)</h2>

<p>在很多语言中，你并不需要去关注堆和栈的概念，但是在系统编程语言中，你需要对此有一定的了解，后面讲到的所有权需要用到堆和栈的概念。</p>

<p>堆和栈具有不同的结构，栈存入数据和取出数据的顺序是相反的，比如你首先放入堆的数据将最后才能取出。堆必须声明确定的不可改变的大小。如果一个数据结构的大小是不确定的或者是会变化的，则需要使用堆数据结构。当将一个数据放入到堆中时，需要先申请一块内存地址，然后返回其指针。这与栈不同，将数据入栈是不需要申请内存的。</p>

<p>When your code calls a function, the values passed into the function (including, potentially, pointers to data on the heap) and the function’s local variables get pushed onto the stack. When the function is over, those values get popped off the stack.</p>

<h2 id="所有权规则">所有权规则</h2>

<p>所有权具有如下的规则：</p>

<ul>
<li>Rust中的每一个数据都有一个叫做所有者(owner)的变量与之关联；</li>
<li>每个数据在同一时刻只能有一个所有者</li>
<li>在数据的所有者的作用范围之外，数据将会dropped(Rust的术语，数据处于未初始化状态)。</li>
</ul>

<h2 id="变量作用域-variable-scope">变量作用域 variable scope</h2>

<p>作用域是一段代码有效的区域。 a scope is the range within a program for which  an item is valid.</p>

<h2 id="类型-string">类型 String</h2>

<p>基本数据类型都存放在栈中，在超出其作用域时，变量会被弹出栈中。</p>

<p>字符串字面量(string literals) 是一个大小确定的数组(个人理解)。<code>String</code>是存储在堆上，并且可以存储一些在编译器无法确定的数据的变量类型。可以通过如下的<code>from</code>函数将字符串字面量转变为<code>String</code>类型。</p>

<pre><code class="language-rust">let s = String::from(&quot;hello&quot;);
// 可修改的string
let mut s = String::from(&quot;hello&quot;);
s.push_str(&quot;, world&quot;);
println!(&quot;{}&quot;, s);
</code></pre>

<h3 id="内存">内存</h3>

<p>字符串字面量是在编译器就确定好的，so the text is hardcoded directly into the final executable. 因此字面量效率更高，但是这些优点是建立在字面量无法修改的前提下，不幸的是，我们无法将字面量使用于在编译器无法确定的变量或者在运行期需要修改的变量上。</p>

<p>为解决这个问题，<code>String</code>需要能满足可修改，可增长大小。因此我们需要在堆上申请一块编译期无法明确大小的内存区域来存放内容。即：</p>

<ul>
<li>具体的内存申请需要在运行期操作</li>
<li>需要一种机制，可以在用完这个string后将内存返还给系统</li>
</ul>

<p>再次分析上面的代码，已经完成了第一步，在运行期根据实际情况申请特定大小的内存区域完成变量初始化。这同其他语言大致一样。而对于第二步，使用gc的编程语言gc可以保证内存在变量不再使用时释放掉；没有gc的编程语言，需要手动的释放内存，这要求<code>allocate</code>和<code>free</code>必须成对存在，不能多一个也不能少一个，要不然会造成各种bug。</p>

<pre><code class="language-rust">let s = String::from(&quot;hello&quot;);
// 此时在运行期申请内存
</code></pre>

<p>对于第二步，Rust takes a different path: the memory is automatically returned once the variable that owns it goes out of scope.</p>

<pre><code class="language-rust">#![allow(unused_variables)]
fn main() {
    {
        let s = String::from(&quot;hello&quot;);  // s is valid from this point forward

        // do stuff with s
    }                    // this scope is now over, and s is no longer valid
}
</code></pre>

<p>When a variable goes out of scope, Rust calls a special function <code>drop</code> for us.</p>

<h3 id="ways-variables-and-data-interact-move">ways variables and data interact: move</h3>

<p>第一个例子，关于简单变量的。</p>

<pre><code class="language-rust">#![allow(unused_variables)]
fn main() {
    let x = 5;
    let y = x;
}
</code></pre>

<p>执行流程： “bind the value 5 to x; then make a copy of the value in x and bind it to y.”  We now have two variables, x and y, and both equal 5. This is indeed what is happening, because integers are simple values with a known, fixed size, and these two 5 values are pushed onto the stack.</p>

<p>第二个例子，关于String</p>

<pre><code class="language-rust">#![allow(unused_variables)]
fn main() {
    let s1 = String::from(&quot;hello&quot;);
    let s2 = s1;
    // println!(&quot;{}&quot;, s1);
    // 这是一个错误的操作，因为s1现在已经处于未初始化状态，不能访问其内容
}
</code></pre>

<p>如果此时和基本变量一样的内存处理形式的话，则会是的s1和s2的data部分都指向了堆中的hello的首地址处，当s1和s2的作用域失效时，rust会自动的将两个变量指向的内存区域执行free操作，这是不合适的，会造成double free 的问题，rust为了解决这种问题，提出了在对s2赋值s1时，会将s1的数据指向清空，此时s1变成未初始化状态。</p>

<p>In this example, we would say that s1 was moved into s2</p>

<h3 id="ways-variables-and-data-interact-clone">ways variables and data interact： clone</h3>

<p>通过clone可以实现创建一个新的内存区域的功能。</p>

<pre><code class="language-rust">#![allow(unused_variables)]
fn main() {
    let s1 = String::from(&quot;hello&quot;);
    let s2 = s1.clone();

    println!(&quot;s1 = {}, s2 = {}&quot;, s1, s2);
}
</code></pre>

<h2 id="stack-only-data-copy">stack-only data: copy</h2>

<p>只存在于栈上的数据，已经实现了copy这个功能，不用使用clone就可以实现数据的复制。</p>

<pre><code class="language-rust">
#![allow(unused_variables)]
fn main() {
    let x = 5;
    let y = x;

    println!(&quot;x = {}, y = {}&quot;, x, y);
}
</code></pre>

<p>The reason is that types such as integers that have a known size at compile time are stored entirely on the stack, so copies of the actual values are quick to make. That means there’s no reason we would want to prevent x from being valid after we create the variable y. In other words, there’s no difference between deep and shallow copying here, so calling clone wouldn’t do anything different from the usual shallow copying and we can leave it out.</p>

<p>Rust has a special annotation called the Copy trait that we can place on types like integers that are stored on the stack. If a type has the Copy trait, an older variable is still usable after assignment.</p>

<p>Here are some of the types that are Copy:</p>

<ul>
<li>All the integer types, such as u32.</li>
<li>The Boolean type, bool, with values true and false.</li>
<li>All the floating point types, such as f64.</li>
<li>The character type, char.</li>
<li>Tuples, if they only contain types that are also Copy. For example, (i32, i32) is Copy, but (i32, String) is not.</li>
</ul>

<h3 id="ownership-and-functions">ownership and functions</h3>

<p>The semantics for passing a value to a function are similar to those for assigning a value to a variable. Passing a variable to a function will move or copy, just as assignment does.</p>

<pre><code class="language-rust">fn main() {
    let s = String::from(&quot;hello&quot;);  // s comes into scope

    takes_ownership(s);             // s's value moves into the function...
                                    // ... and so is no longer valid here

    let x = 5;                      // x comes into scope

    makes_copy(x);                  // x would move into the function,
                                    // but i32 is Copy, so it’s okay to still
                                    // use x afterward

} // Here, x goes out of scope, then s. But because s's value was moved, nothing
  // special happens.

fn takes_ownership(some_string: String) { // some_string comes into scope
    println!(&quot;{}&quot;, some_string);
} // Here, some_string goes out of scope and `drop` is called. The backing
  // memory is freed.

fn makes_copy(some_integer: i32) { // some_integer comes into scope
    println!(&quot;{}&quot;, some_integer);
} // Here, some_integer goes out of scope. Nothing special happens.

</code></pre>

<h3 id="return-values-and-scope">return values and scope</h3>

<p>Returning values can also transfer ownership</p>

<pre><code class="language-rust">fn main() {
    let s1 = gives_ownership();         // gives_ownership moves its return
                                        // value into s1

    let s2 = String::from(&quot;hello&quot;);     // s2 comes into scope

    let s3 = takes_and_gives_back(s2);  // s2 is moved into
                                        // takes_and_gives_back, which also
                                        // moves its return value into s3
} // Here, s3 goes out of scope and is dropped. s2 goes out of scope but was
  // moved, so nothing happens. s1 goes out of scope and is dropped.

fn gives_ownership() -&gt; String {             // gives_ownership will move its
                                             // return value into the function
                                             // that calls it

    let some_string = String::from(&quot;hello&quot;); // some_string comes into scope

    some_string                              // some_string is returned and
                                             // moves out to the calling
                                             // function
}

// takes_and_gives_back will take a String and return one
fn takes_and_gives_back(a_string: String) -&gt; String { // a_string comes into
                                                      // scope

    a_string  // a_string is returned and moves out to the calling function
}

</code></pre>

<p>The ownership of a variable follows the same pattern every time: assigning a value to another variable moves it. When a variable that includes data on the heap goes out of scope, the value will be cleaned up by drop unless the data has been moved to be owned by another variable.</p>

<p>Taking ownership and then returning ownership with every function is a bit tedious. What if we want to let a function use a value but not take ownership? It’s quite annoying that anything we pass in also needs to be passed back if we want to use it again, in addition to any data resulting from the body of the function that we might want to return as well.</p>

<h2 id="references-and-borrowing">references and borrowing</h2>

<p>These ampersands(&amp;) are references, and they allow you to refer to some value without taking ownership of it. 使用&amp;让其他变量可以访问数据而不用放弃所有权。</p>

<pre><code class="language-rust">
#![allow(unused_variables)]
fn main() {
    fn calculate_length(s: &amp;String) -&gt; usize { // s is a reference to a String
        s.len()
    } // Here, s goes out of scope. But because it does not have ownership of what
      // it refers to, nothing happens.
    let s1 = String::from(&quot;hello&quot;);

    // &amp;s1 让我们创建一个变量，指向了s1的内容，但是却不占用其所有权
    let len = calculate_length(&amp;s1);
}

#![allow(unused_variables)]
fn main() {
    
}
</code></pre>

<p>We call having references as function parameters borrowing. 可以借用一个references，但是不能修改它，也不能转借，用完归还。</p>

<h3 id="mutable-references">Mutable References</h3>

<p>mutable reference 可以解决无法修改的问题，但是只能使用一次mutable reference， 因为借出之后，此变量的所有权已经不再被拥有，无法出借一个无所有权的变量。</p>

<pre><code class="language-rust">let mut s = String::from(&quot;hello&quot;);

let r1 = &amp;mut s;
let r2 = &amp;mut s;

println!(&quot;{}, {}&quot;, r1, r2);
/*
error[E0499]: cannot borrow `s` as mutable more than once at a time
 --&gt; src/main.rs:5:14
  |
4 |     let r1 = &amp;mut s;
  |              ------ first mutable borrow occurs here
5 |     let r2 = &amp;mut s;
  |              ^^^^^^ second mutable borrow occurs here
6 |
7 |     println!(&quot;{}, {}&quot;, r1, r2);
  |                        -- first borrow later used here
  */

</code></pre>

<p>Note that a reference&rsquo;s scope starts from where it is introduced and continues through the last time that reference is used.</p>

<p>references 从出现开始，到被使用一次结束，使用时就会出现move，然后drop。</p>

<pre><code class="language-rust">let mut s = String::from(&quot;hello&quot;);

let r1 = &amp;s; // no problem
let r2 = &amp;s; // no problem
println!(&quot;{} and {}&quot;, r1, r2);
// r1 and r2 are no longer used after this point

let r3 = &amp;mut s; // no problem
println!(&quot;{}&quot;, r3);

</code></pre>

<h3 id="dangling-reference">dangling reference</h3>

<p>在其他使用指针的编程语言中，经常会出现悬空指针，即指针指向了一个已经不再使用的内存块。rust在编译期保证不会出现这种情况。</p>

<pre><code class="language-rust">fn dangle() -&gt; &amp;String { // dangle returns a reference to a String

    let s = String::from(&quot;hello&quot;); // s is a new String

    &amp;s // we return a reference to the String, s
} // Here, s goes out of scope, and is dropped. Its memory goes away.
  // Danger!
</code></pre>

<p>修改后：使用move来传递生命周期。</p>

<pre><code class="language-rust">
#![allow(unused_variables)]
fn main() {
    fn no_dangle() -&gt; String {
        let s = String::from(&quot;hello&quot;);

        s
    }
}
</code></pre>

<p>Let’s recap what we’ve discussed about references:</p>

<ul>
<li>At any given time, you can have either one mutable reference or any number of immutable references.</li>
<li>References must always be valid.</li>
</ul>

<h3 id="string-slice">String slice</h3>

<p>The type that signifies “string slice” is written as &amp;str。</p>

<pre><code class="language-rust">
#![allow(unused_variables)]
fn main() {
    fn first_word(s: &amp;String) -&gt; &amp;str {
        let bytes = s.as_bytes();

        for (i, &amp;item) in bytes.iter().enumerate() {
            if item == b' ' {
                return &amp;s[0..i];
            }
        }

        &amp;s[..]
    }
}
</code></pre>

<p>string literals are slices.</p>

<pre><code class="language-rust">#![allow(unused_variables)]
fn main() {
    let s = &quot;Hello, world!&quot;;
}
</code></pre>

<p>The type of s here is &amp;str: it’s a slice pointing to that specific point of the binary. This is also why string literals are immutable; &amp;str is an immutable reference.</p>

<h2 id="validating-references-with-lifetimes">validating references with lifetimes</h2>

<p>we must annotate lifetimes when the lifetimes of references could be related in a few different ways.</p>

<p>Lifetime annotations describe the relationships of the lifetimes of multiple references to each other without affecting the lifetimes.</p>

<p>We place lifetime parameter annotations after the &amp; of a reference, using a space to separate the annotation from the reference’s type.</p>

<p>示例：</p>

<pre><code class="language-rust">#![allow(unused_variables)]
fn main() {
    // 这是错误的，因为返回一个借用，但是声明中并没有说明是哪个借用
    fn longest(x: &amp;str, y: &amp;str) -&gt; &amp;str {
        if x.len() &gt; y.len() {
            x
        } else {
            y
        }
    }

    // ok , 声明了生命周期，这两个借用，在整个函数中都是有效的？
    fn longest&lt;'a&gt;(x: &amp;'a str, y: &amp;'a str) -&gt; &amp;'a str {
        if x.len() &gt; y.len() {
            x
        } else {
            y
        }
    }
}
</code></pre>

<p>Note that the longest function doesn’t need to know exactly how long x and y will live, only that some scope can be substituted for &lsquo;a that will satisfy this signature.</p>

<h3 id="lifetime-elision">lifetime elision</h3>

<pre><code class="language-rust">
#![allow(unused_variables)]
fn main() {
    fn first_word(s: &amp;str) -&gt; &amp;str {
        let bytes = s.as_bytes();

        for (i, &amp;item) in bytes.iter().enumerate() {
            if item == b' ' {
                return &amp;s[0..i];
            }
        }

        &amp;s[..]
    }
}
</code></pre>

<p>上面代码可以正常编译是有历史原因的，在最初的时候是不可以的，但是后来发现这种代码很多，于是编译器就加了功能，不再检测这个lifetime问题。</p>

<p>This piece of Rust history is relevant because it’s possible that more deterministic patterns will emerge and be added to the compiler. In the future, even fewer lifetime annotations might be required.</p>

<p>Lifetimes on function or method parameters are called input lifetimes, and lifetimes on return values are called output lifetimes.</p>

<p>编译器有三条规则用于推算lifetime references。第1条作用于输入参数，第二条和第三条作用于返回值。当三条规则都无法推算出生命周期时，编译器会报错。</p>

<ul>
<li>The first rule is that each parameter that is a reference gets its own lifetime parameter. In other words, a function with one parameter gets one lifetime parameter: fn foo&lt;&lsquo;a&gt;(x: &amp;&lsquo;a i32); a function with two parameters gets two separate lifetime parameters: fn foo&lt;&lsquo;a, &lsquo;b&gt;(x: &amp;&lsquo;a i32, y: &amp;&lsquo;b i32); and so on.</li>
<li>The second rule is if there is exactly one input lifetime parameter, that lifetime is assigned to all output lifetime parameters: fn foo&lt;&lsquo;a&gt;(x: &amp;&lsquo;a i32) -&gt; &amp;&lsquo;a i32.</li>
<li>The third rule is if there are multiple input lifetime parameters, but one of them is &amp;self or &amp;mut self because this is a method, the lifetime of self is assigned to all output lifetime parameters. This third rule makes methods much nicer to read and write because fewer symbols are necessary.</li>
</ul>

<p>简单来说：</p>

<ul>
<li>每个输入参数都有一个属于自己的生命周期注解</li>
<li>如果输入中只有一个生命周期注解，那么这个生命周期会默认添加到返回值中</li>
<li>如果输入中有多个什么周期注解，但是其中有个是 &amp;self 或 &amp;mut self，那么这个注解将用于返回</li>
</ul>

<h3 id="lifetime-annotations-in-method-definition">lifetime annotations in method definition</h3>

<p>？？？？</p>

<h3 id="static-lifetime">static lifetime</h3>

<p>One special lifetime we need to discuss is &lsquo;static, which means that this reference can live for the entire duration of the program. All string literals have the &lsquo;static lifetime, which we can annotate as follows:</p>

<pre><code class="language-rust">#![allow(unused_variables)]
fn main() {
    let s: &amp;'static str = &quot;I have a static lifetime.&quot;;
}
</code></pre>
                        </div>

                        


                        

<div class="post-archive">
    <h2>See Also</h2>
    <ul class="listing">
        
        <li><a href="/hugo/post/lang/rust-programing/">Rust Programing</a></li>
        
    </ul>
</div>


                        <div class="post-meta meta-tags">
                            
                            <ul class="clearfix">
                                
                                <li><a href="https://otswang.gitee.io/hugo/tags/rust">Rust</a></li>
                                
                            </ul>
                            
                        </div>
                    </article>
                    
    

    
    
                </div>
            </div>
            <div id="secondary">

    <section class="widget">
        <form id="search" action="//www.google.com/search" method="get" accept-charset="utf-8" target="_blank" _lpchecked="1">
      
      <input type="text" name="q" maxlength="20" placeholder="Search">
      <input type="hidden" name="sitesearch" value="https://otswang.gitee.io/hugo/">
      <button type="submit" class="submit icon-search"></button>
</form>
    </section>

    
    <div class="clear">
        <div class="toc-article">
            <div class="toc-title">文章目录</dixsv>
            <nav id="TableOfContents">
<ul>
<li>
<ul>
<li><a href="#堆-heap-栈-stack">堆(heap)栈(stack)</a></li>
<li><a href="#所有权规则">所有权规则</a></li>
<li><a href="#变量作用域-variable-scope">变量作用域 variable scope</a></li>
<li><a href="#类型-string">类型 String</a>
<ul>
<li><a href="#内存">内存</a></li>
<li><a href="#ways-variables-and-data-interact-move">ways variables and data interact: move</a></li>
<li><a href="#ways-variables-and-data-interact-clone">ways variables and data interact： clone</a></li>
</ul></li>
<li><a href="#stack-only-data-copy">stack-only data: copy</a>
<ul>
<li><a href="#ownership-and-functions">ownership and functions</a></li>
<li><a href="#return-values-and-scope">return values and scope</a></li>
</ul></li>
<li><a href="#references-and-borrowing">references and borrowing</a>
<ul>
<li><a href="#mutable-references">Mutable References</a></li>
<li><a href="#dangling-reference">dangling reference</a></li>
<li><a href="#string-slice">String slice</a></li>
</ul></li>
<li><a href="#validating-references-with-lifetimes">validating references with lifetimes</a>
<ul>
<li><a href="#lifetime-elision">lifetime elision</a></li>
<li><a href="#lifetime-annotations-in-method-definition">lifetime annotations in method definition</a></li>
<li><a href="#static-lifetime">static lifetime</a></li>
</ul></li>
</ul></li>
</ul>
</nav>
        </div>
    </div>
    

</div>
        </div>
    </div>
</div>
<footer id="footer">
    <div class="container">
        &copy; 2020 <a href="https://otswang.gitee.io/hugo/">The Sky of OtsWang By OtsWang</a>.
        Powered by <a rel="nofollow noreferer noopener" href="https://gohugo.io" target="_blank">Hugo</a>.
        <a href="https://www.flysnow.org/" target="_blank">Theme</a> based on <a href="https://github.com/Dudiao137/maupassant-hugo" target="_blank">maupassant-ots</a>.
        
    </div>
</footer>


    <script type="text/javascript">
    
    (function(){
        $("pre code").parent().addClass("line-numbers")
    }())

    window.MathJax = {
        tex2jax: {
            inlineMath: [ ['$','$'] ],
            processEscapes: true
        }
    };
    </script>
    <script type="text/javascript" src="/hugo/js/prism.js" async="true"></script>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML' async></script>

<a id="rocket" href="#top"></a>
<script type="text/javascript" src="/hugo/js/totop.js?v=0.0.0" async=""></script>







 
 <script src="https://mermaidjs.github.io/scripts/mermaid.min.js"></script>
 <script>
       mermaid.initialize({ startOnLoad: true });
 </script>
</body>
</html>
